package com.chat.common.user.service.impl;

import cn.hutool.core.thread.NamedThreadFactory;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.chat.common.common.domain.vo.resp.ApiResult;
import com.chat.common.common.handler.GlobalUncaughtExceptionHandler;
import com.chat.common.common.utils.JsonUtils;
import com.chat.common.user.dao.UserDao;
import com.chat.common.user.domain.entity.IpDetail;
import com.chat.common.user.domain.entity.IpInfo;
import com.chat.common.user.domain.entity.User;
import com.chat.common.user.service.IpService;
import com.chat.common.user.service.cache.UserCache;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class IpServiceImpl implements IpService {

    private static final ExecutorService EXECUTOR = new ThreadPoolExecutor(1, 1,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(500),
            new NamedThreadFactory("refresh-ipDetail", null, false,
                    GlobalUncaughtExceptionHandler.getInstance()));

    @Resource
    private UserDao userDao;
    @Resource
    private UserCache userCache;

    @Override
    public void refreshIpDetail(Long id) {
        EXECUTOR.execute(()->{
            User user = userDao.getById(id);
            IpInfo ipInfo = user.getIpInfo();
            if(Objects.isNull(ipInfo)){
                return;
            }
            String ip = ipInfo.needRefreshIp();
            if(StringUtils.isBlank(ip)){
                return;
            }
            IpDetail ipDetail = TryGetIpDetailOrNullTreeTimes(ip);
            if(Objects.nonNull(ipDetail)){
                //更新detail
                ipInfo.refreshIpDetail(ipDetail);
                User update = new User();
                update.setId(id);
                update.setIpInfo(ipInfo);
                userDao.updateById(update);
            }
        });

    }

    @Override
    public void refreshIpDetailAsync(Long uid) {
        EXECUTOR.execute(() -> {
            User user = userDao.getById(uid);
            IpInfo ipInfo = user.getIpInfo();
            if (Objects.isNull(ipInfo)) {
                return;
            }
            String ip = ipInfo.needRefreshIp();
            if (StrUtil.isBlank(ip)) {
                return;
            }
            IpDetail ipDetail = TryGetIpDetailOrNullTreeTimes(ip);
            if (Objects.nonNull(ipDetail)) {
                ipInfo.refreshIpDetail(ipDetail);
                User update = new User();
                update.setId(uid);
                update.setIpInfo(ipInfo);
                userDao.updateById(update);
                userCache.userInfoChange(uid);
            } else {
                log.error("get ip detail fail ip:{},uid:{}", ip, uid);
            }

        });
    }

    private IpDetail TryGetIpDetailOrNullTreeTimes(String ip) {
        for (int i = 0; i < 3; i++) {
            IpDetail ipDetail =  getIpDetailOrNull(ip);
            if(Objects.nonNull(ipDetail)){
                return ipDetail;
            }
            try {
                Thread.sleep(1000);
            }catch (InterruptedException e){
                log.error("TryGetIpDetailOrNullTreeTimes InterruptedException",e);
            }
        }
        return null;
    }

    private IpDetail getIpDetailOrNull(String ip) {
        String url = "https://ip.taobao.com/outGetIpInfo?ip="+ip+"&accessKey=alibaba-inc";
        String data = HttpUtil.get(url);
        ApiResult<IpDetail> detailApiResult = JsonUtils.toObj(data, new TypeReference<ApiResult<IpDetail>>() {});
        IpDetail resultData = detailApiResult.getData();
        return resultData;
    }
}
